home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Tcl / SystemCode / indentation.tcl < prev    next >
Encoding:
Text File  |  2000-12-18  |  19.0 KB  |  659 lines

  1. ## -*-Tcl-*-
  2.  # ###################################################################
  3.  #  AlphaTcl - core Tcl engine
  4.  # 
  5.  #    FILE: "indentation.tcl"
  6.  #                      created: 27/7/97 {1:08:08 am}    
  7.  #                     last update: 12/18/2000 {11:02:09 AM}    
  8.  #    Author:    Vince Darley
  9.  #    E-mail:    <vince@santafe.edu>
  10.  #      mail:    317 Paseo de Peralta, Santa Fe, NM 87501, USA
  11.  #       www:    <http://www.santafe.edu/~vince/>
  12.  #    
  13.  # 
  14.  #  modified   by  rev reason
  15.  #  ---------- --- --- -----------
  16.  #  2000-12-07 DWH 0.1 updated help text for electricReturn
  17.  # ###################################################################
  18.  ##
  19.  
  20. alpha::flag electricBraces 0.1 Electrics {global C C++ Java Tcl Perl} help {
  21.     Enabling the 'Electric Braces' feature tells Alpha to treat the 
  22.     left or right brace '{', '}' keys as special keypresses which 
  23.     enter the '{' or '}' character, followed by a return and then 
  24.     indent the following line correctly.  It is useful for those 
  25.     programming modes in which '{' and '}' are used to delineate 
  26.     blocks of code in 'for' loops or 'if-then-else' groups etc.
  27. }
  28.  
  29. alpha::flag electricSemicolon 0.1 Electrics {global C C++ Java Perl} help {
  30.     Enabling the 'Electric Semicolon' feature tells Alpha to treat the 
  31.     semicolon key ';' as special keypresses which enters the ';' 
  32.     character followed by a return and then indents the following line 
  33.     correctly.  It is useful for some programming modes in which ';' 
  34.     normally ends a line.
  35.     
  36.     The ';' key is context-dependent so you can still enter a 
  37.     for( ; ; ) loop in C mode (for instace) without Alpha messing 
  38.     things up.
  39. }
  40.  
  41. alpha::declare flag electricReturn 0.1 {global} {
  42.     if {[info tclversion] >= 8.0} {
  43.     linkVar indentOnReturn
  44.     }
  45.     set indentOnReturn 0
  46.     lappend flagPrefs(Electrics) electricReturn
  47. } {set indentOnReturn 1} {set indentOnReturn 0} help {
  48.     Enabling the 'Electric Return' feature tells Alpha to indent the 
  49.     following line automatically whenever you press return.
  50.     
  51.     Press <control>-<return> to over-ride this behavior, to insert a
  52.     carriage return without indenting.
  53. }
  54.  
  55. alpha::flag electricColon 0.1 Electrics {global} help {
  56.     Enabling the 'Electric Colon' feature tells Alpha to carry out a 
  57.     special action when the user presses colon.
  58. }
  59.  
  60. alpha::flag autoContinueComment 0.1 Electrics {global} help {
  61.     Enabling the 'autoContinueComment' feature tells Alpha to check when
  62.     the users hits return whether the current line is a comment, and if
  63.     so, to indent and insert comment characters so that the following
  64.     line continues the comment.
  65. }
  66.  
  67. alpha::flag indentUsingSpacesOnly 0.1 Electrics {global TeX} help {
  68.     If set, do not use tabs to indent, but spaces only.  This is mostly
  69.     useful for modes in which the 'tab' character has a special meaning,
  70.     such as python or TeX (the latter usually only for TeX as a programming
  71.     language, not as a document preparation system).
  72. }
  73.  
  74. alpha::flag commentsArentSpecialWhenIndenting 0.1 Electrics {global TeX} help {
  75.     Indent lines to level of previous line if set, otherwise to level 
  76.     of previous non-comment line (in which case Alpha will search 
  77.     backwards for some distance).  If you're in the habit of indenting 
  78.     your comments to the same level as your code, this setting 
  79.     shouldn't matter (and setting it is slightly more efficient).
  80.     
  81.     One case in which it can be _much_ more efficient is when your 
  82.     files contain vast comments (especially .dtx files in TeX mode, 
  83.     for instance).  For these files, you should activate this feature.
  84. }
  85.  
  86. namespace eval indent {}
  87. namespace eval Bind {}
  88. namespace eval text {}
  89.  
  90. proc IndentLine {} { bind::IndentLine }
  91.  
  92. proc typeText {t} {
  93.     if {[isSelection]} {
  94.     deleteSelection
  95.     }
  96.     insertText $t
  97. }
  98.  
  99. proc normalLeftBrace {} {
  100.     typeText "\{"
  101. }
  102. proc normalRightBrace {} {
  103.     typeText "\}"
  104.     blink [matchIt "\}" [pos::math [getPos] - 2]]
  105. }
  106.             
  107. proc literalChar {} {
  108.     return [expr {[lookAt [pos::math [getPos] - 1]] == "\\"}]
  109. }
  110.  
  111. # ◊◊◊◊ Electric indentation ◊◊◊◊ #
  112. proc bind::LeftBrace {} {
  113.     if {[isSelection]} { deleteSelection }
  114.     global electricBraces mode
  115.     if {!$electricBraces} {
  116.     insertText "\{"
  117.     return
  118.     }
  119.     mode::proc electricLeft
  120. }
  121.  
  122. proc ::electricLeft {} {
  123.     if {![catch {search -l [lineStart [pos::math [lineStart [getPos]] - 1]] \
  124.       -s -f 0 -r 0 "\}" [getPos]} res]} {
  125.     set end [getPos]
  126.     if {[pos::compare [getPos] != [maxPos]]} {
  127.         set end [pos::math $end + 1]
  128.     }
  129.     
  130.     if {[regexp -- "\}\[ \t\r\n\]*else" [getText [lindex $res 0] $end]]} {
  131.         set res2 [search -s -f 0 -r 1 {else} [getPos]]
  132.         oneSpace
  133.         set text [getText [lindex $res2 0] [getPos]]
  134.         if {[lookAt [pos::math [getPos] - 1]] != " "} {
  135.         append text " "
  136.         }
  137.         replaceText [pos::math [lindex $res 0] + 1] [getPos] " $text\{\r"
  138.         bind::IndentLine
  139.         return 
  140.     }
  141.     }
  142.     set pos [getPos]
  143.     set i [text::firstNonWsLinePos $pos]
  144.     
  145.     if {([pos::compare $i == $pos]) || ([lookAt [pos::math $pos - 1]] == " ")} {
  146.     insertText "\{\r" [text::indentString $pos] [text::Tab]
  147.     } else {
  148.     insertText " \{\r" [text::indentString $pos] [text::Tab]
  149.     }
  150. }
  151.  
  152. proc ::electricRight {} {
  153.     set pos [getPos]
  154.     set start [lineStart $pos]
  155.     
  156.     if {[catch {matchIt "\}" [pos::math $pos - 1]} matched]} {
  157.     beep
  158.     message "No matching '\{'!"
  159.     return
  160.     }
  161.     set text [getText [lineStart $matched] $matched]
  162.     regexp "^\[ \t\]*" $text indentation
  163.     if {[string trim [getText $start $pos]] != ""} {
  164.     insertText "\r" $indentation "\}\r" $indentation
  165.     blink $matched
  166.     return
  167.     }
  168.     set text "${indentation}\}\r$indentation"
  169.     replaceText $start $pos $text
  170.     goto [pos::math $start + [string length $text]]
  171.     blink [matchIt "\}" [pos::math $start - 2]]
  172. }
  173.  
  174. proc bind::RightBrace {} {
  175.     if {[isSelection]} { deleteSelection }
  176.     global electricBraces mode
  177.     if {!$electricBraces} {
  178.     insertText "\}"
  179.     catch {blink [matchIt "\}" [pos::math [getPos] - 2]]}
  180.     return
  181.     }
  182.     mode::proc electricRight
  183. }
  184.  
  185. proc bind::electricSemi {} {
  186.     global electricSemicolon
  187.     if {!$electricSemicolon} {
  188.     typeText ";"
  189.     return
  190.     }
  191.     mode::proc electricSemi
  192. }
  193.  
  194. proc ::electricSemi {} {
  195.     if {[isSelection]} { deleteSelection }
  196.     set pos [getPos]
  197.     set text [getText [lineStart $pos] $pos]
  198.     
  199.     set inFor 0
  200.     if {[string first "for" $text] != "-1"} {
  201.     set len [string length $text]
  202.     for {set i 0} {$i < $len} {incr i} {
  203.         switch -- [string index $text $i] {
  204.         "("    { incr inFor }
  205.         ")"    { incr inFor -1 }
  206.         }
  207.     }
  208.     }
  209.     
  210.     if {$inFor != 0 || [text::isInComment $pos]} {
  211.     insertText ";"
  212.     } else {
  213.     insertText ";\r" [text::indentString $pos]
  214.     }
  215. }
  216.  
  217. ## 
  218.  # -------------------------------------------------------------------------
  219.  #     
  220.  # "bind::CarriageReturn" --
  221.  #    
  222.  #  General purpose CR procedure.  Should be bound to 'return' for all
  223.  #  modes really.  Calls a mode-specific procedure if required.
  224.  #  
  225.  #  We can force that we are inside a comment with the 'isInComment'
  226.  #  argument.
  227.  # -------------------------------------------------------------------------
  228.  ##
  229. proc bind::CarriageReturn {{isInComment 0}} {
  230.     if {[isSelection]} { deleteSelection }
  231.     global autoContinueComment
  232.     if {$autoContinueComment} {
  233.     set p [getPos]
  234.     if {$isInComment || ([text::isInComment $p start])} {
  235.         # special case for beginning of line
  236.         if {[pos::compare $p == [lineStart $p]]} {
  237.         backwardChar
  238.         }
  239.         if {![info exists start]} {
  240.         global prefixString
  241.         if {[info exists prefixString]} {
  242.             set start $prefixString
  243.         } else {
  244.             set start "/"
  245.         }
  246.         }
  247.         insertText "\r${start}"
  248.         return
  249.     }
  250.     }
  251.     mode::proc carriageReturn
  252. }
  253.  
  254. proc bind::continueComment {} {
  255.     global autoContinueComment
  256.     bind::CarriageReturn $autoContinueComment
  257. }
  258.     
  259.  
  260. proc ::carriageReturn {} {
  261.     insertText "\r"
  262.     global indentOnReturn
  263.     if {$indentOnReturn} {bind::IndentLine}
  264. }
  265.  
  266. proc bind::IndentLine {} {
  267.     mode::proc indentLine
  268. }
  269.  
  270. proc insertActualTab {} { typeText "\t" }
  271.  
  272.  
  273.  
  274. ## 
  275.  # -------------------------------------------------------------------------
  276.  # 
  277.  # "text::isInComment" --
  278.  # 
  279.  # Are we in a block comment? Just checks if both the given line and the
  280.  # next line commence with any of a set of known block-comment characters.
  281.  # Not 100% satisfactory for C comments, but fine for all others.
  282.  # 
  283.  # If 'st' is given, we use it as a variable name in which to store
  284.  # the prefix which will be needed in indenting the following line.
  285.  # -------------------------------------------------------------------------
  286.  ##
  287. proc text::isInComment {pos {st ""}} {
  288.     if {[pos::compare $pos == [minPos]]} {
  289.     return 0
  290.     }
  291.     set p [lineStart $pos]
  292.     if {[pos::compare $pos == $p]} {
  293.     set pos [pos::math $pos - 1] ; set p [lineStart $pos]
  294.     }
  295.     set q [nextLineStart $pos]
  296.     set t [getText $p $q]
  297.     if { $st != "" } {
  298.     upvar $st a
  299.     }
  300.     if {![catch {comment::Characters "Paragraph"} cpar]} {
  301.     if {[regexp -- "^(.*)[quote::Regfind [string trim [lindex $cpar 0]]](.*)" $t "" a rest]} {
  302.         # We found an opening comment
  303.         if {![regexp -indices -- "[quote::Regfind [string trim [lindex $cpar 1]]]" $rest where] \
  304.           || (([string length $rest] - [pos::diff $pos $q] -1) < [lindex $where 0])} {
  305.         # Either we didn't find a closing comment, or we did,
  306.         # and the closing comment was after the position $pos,
  307.         # in which case $pos was still inside the comment.
  308.         # Either way we need to continue the comment.
  309.         regsub -all "\[^ \t\]" $a " " a
  310.         append a [lindex $cpar 2]
  311.         return 1
  312.         }
  313.     }
  314.     }
  315.     # if the next line is a comment 
  316.     set qq [text::firstNonWsLinePos $q]
  317.     if {[pos::compare $qq == [maxPos]]} { 
  318.     return 0 
  319.     }
  320.     foreach commentCh [comment::Characters "General"] {    
  321.     if {[regexp -- "^\[ \t\]*[quote::Regfind ${commentCh}]\[ \t\]*" $t a]} {
  322.         # if we hit return in the middle of a line
  323.         if {[string trim [getText $pos $q]] != "" && [pos::compare $pos != $p]} { 
  324.         return 1
  325.         }
  326.         if {[getText $qq [pos::math $qq + [string length $commentCh]]] == $commentCh} {
  327.         return 1
  328.         }
  329.     }
  330.     }
  331.     return 0
  332. }
  333.  
  334.  
  335. # ◊◊◊◊ Indentation utility routines ◊◊◊◊ #
  336.  
  337. proc posX {pos} {return [lindex [posToRowCol $pos] 1] }
  338. # the above version doesn't work!
  339. if {[info tclversion] < 8.0} {
  340. proc posX {pos} {
  341.     return [string length [text::maxSpaceForm [getText [lineStart $pos] $pos]]]
  342. }
  343. }
  344.  
  345. proc text::firstNonWs {pos} {
  346.     set p [text::firstNonWsPos $pos]
  347.     if {[pos::compare $p > [minPos]]} {
  348.     return [lookAt $p]
  349.     } else {
  350.     return ""
  351.     }
  352. }
  353.  
  354. ## 
  355.  # -------------------------------------------------------------------------
  356.  #   
  357.  # "text::firstNonWsPos" --
  358.  #  
  359.  #  This returns the position of the first non-whitespace character from
  360.  #  the start of pos' line.  It need not return something on the same
  361.  #  line.
  362.  # -------------------------------------------------------------------------
  363.  ##
  364. proc text::firstNonWsPos {pos} {
  365.     if {[catch {lindex [search -s -f 1 -r 1 "\[^ \t\r\n\]" [lineStart $pos]] 0} res]} {
  366.     return [lineStart $pos]
  367.     } else {
  368.     return $res
  369.     }
  370. }
  371.  
  372. proc text::firstNonWsLinePos {pos} {
  373.     if {[catch {lindex [search -s -f 1 -r 1 "\[^ \t\]" [lineStart $pos]] 0} res]} {
  374.     return [lineStart $pos]
  375.     } else {
  376.     return $res
  377.     }
  378. }
  379.  
  380. proc text::indentation {pos} {
  381.     return [search -s -m 0 -f 1 -r 1 "^\[ \t\]*\[^ \t\]" [lineStart $pos]]
  382. }
  383.  
  384. ## 
  385.  # -------------------------------------------------------------------------
  386.  # 
  387.  # "text::minSpaceForm" --
  388.  # 
  389.  #  Converts to minimal form: tabs then spaces.  Uses one regsub to do
  390.  #  the job.  Note that the regexp used relies upon the left-to-right
  391.  #  priority of branch matching.  If the regexp library used is more
  392.  #  sophisticated and finds maximal matches, then this is no good.
  393.  #  In that case use:
  394.  #        regsub -all $sp $ws "\t" ws
  395.  #        regsub -all " +\t" $ws "\t" ws
  396.  # -------------------------------------------------------------------------
  397.  ##
  398. if {[info tclversion] < 8.1} {
  399.     proc text::minSpaceForm {ws} {
  400.     if {[string length [set sp [spacesEqualTab]]]} {
  401.         regsub -all "($sp| +\t)" $ws "\t" ws
  402.     } else {
  403.         regsub -all "\t" $ws "" ws
  404.     }
  405.     return $ws
  406.     }
  407. } else {
  408.     proc text::minSpaceForm {ws} {
  409.     if {[string length [set sp [spacesEqualTab]]]} {
  410.         regsub -all $sp $ws "\t" ws
  411.         regsub -all " +\t" $ws "\t" ws
  412.     } else {
  413.         regsub -all "\t" $ws "" ws
  414.     }
  415.     return $ws
  416.     }
  417. }
  418.  
  419.  
  420. ## 
  421.  # -------------------------------------------------------------------------
  422.  # 
  423.  # "text::maxSpaceForm" --
  424.  # 
  425.  #  Converts it to maximal form - just spaces.
  426.  #  Just uses one funky regsub to do the job!  Takes account of tab-size,
  427.  #  spaces interspersed with tabs,...
  428.  # -------------------------------------------------------------------------
  429.  ##
  430. if {[info tclversion] < 8.1} {
  431.     proc text::maxSpaceForm {ws} {
  432.     if {[string length [set sp [spacesEqualTab]]]} {
  433.         regsub -all "(($sp)*) *\t" $ws "\\1$sp" ws
  434.     } else {
  435.         regsub -all "\t" $ws "" ws
  436.     }
  437.     return $ws
  438.     }
  439. } else {
  440.     proc text::maxSpaceForm {ws} {
  441.     if {[string length [set sp [spacesEqualTab]]]} {
  442.         regsub -all $sp $ws "\t" ws
  443.         regsub -all " +\t" $ws "\t" ws
  444.         regsub -all "\t" $ws "$sp" ws
  445.     } else {
  446.         regsub -all "\t" $ws "" ws
  447.     }
  448.     return $ws
  449.     }
  450. }
  451.  
  452.  
  453. ## 
  454.  # -------------------------------------------------------------------------
  455.  # 
  456.  # "spacesEqualTab" --
  457.  # 
  458.  #  Return the number of spaces equivalent to a single tab. If tabs are too
  459.  #  big, this won't work.
  460.  # -------------------------------------------------------------------------
  461.  ##
  462. proc spacesEqualTab {} {
  463.     getWinInfo a
  464.     string range "              " 1 $a(tabsize)
  465. }
  466.  
  467. proc doubleLookAt {pos} {return [getText $pos [pos::math $pos + 2]]}
  468.  
  469. set bind::_IndentSpaces "                                                   \
  470.                                          "
  471. set bind::_IndentTabs "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
  472.  
  473. proc text::indentOf {size} {
  474.     global bind::_IndentSpaces bind::_IndentTabs indentUsingSpacesOnly
  475.     if {$indentUsingSpacesOnly} {
  476.     return [string range ${bind::_IndentSpaces} 1 $size]
  477.     } else {
  478.     getWinInfo a
  479.     if {$a(tabsize) == 0} {
  480.         return [string range ${bind::_IndentSpaces} 1 $size]
  481.     } else {
  482.         set ret [string range ${bind::_IndentTabs} 1 [expr {$size / $a(tabsize)}]]
  483.         append ret [string range ${bind::_IndentSpaces} 1 [expr {$size % $a(tabsize)}]]
  484.     }
  485.     }
  486.     return $ret
  487. }
  488.  
  489. # returns the indent string of the line named by 'pos'
  490. proc text::indentString {pos} {
  491.     set beg [lineStart $pos]
  492.     regexp "^\[ \t\]*" [getText $beg [nextLineStart $beg]] white
  493.     return $white
  494. }
  495.  
  496. # returns the indent string of the line up to position 'pos' 
  497. proc text::indentTo {pos} {
  498.     regexp "^\[ \t\]*" [getText [lineStart $pos] $pos] white
  499.     return $white
  500. }
  501.  
  502. ## 
  503.  # -------------------------------------------------------------------------
  504.  # 
  505.  # "text::indentBy" --
  506.  # 
  507.  #  Take the given block of text, and insert/remove spaces and tabs to
  508.  #  indent it $by spaces to the left or right. This version should work
  509.  #  ok for Tcl 7.5/8.0/8.1
  510.  # -------------------------------------------------------------------------
  511.  ##
  512. proc text::indentBy {text by} {
  513.     global bind::_IndentSpaces indentUsingSpacesOnly
  514.     set sp [spacesEqualTab]
  515.     # Convert all leading whitespace to spaces
  516.     if {[string length $sp]} {
  517.     while {[regsub -all "((^|\r|\n)($sp)*) *\t" $text "\\1$sp" text]} {}
  518.     } else {
  519.     while {[regsub -all "(^|\r|\n)( *)\t" $text "\\1" text]} {}
  520.     }
  521.     set sby [string range ${bind::_IndentSpaces} 1 [expr {abs($by)}]]
  522.     if {$by < 0} {
  523.     # need to indent less
  524.     regsub -all "(^|\r|\n)$sby" $text "\\1" text
  525.     } else {
  526.     # need to indent more: add spaces to beginning of each line,
  527.     # apart from blank lines and the final line
  528.     regsub -all "\[\r\n\](\[^\r\n\])" $sby$text "\r$sby\\1" text
  529.     }
  530.     # We already converted everything to spaces, so we only convert
  531.     # to tabs if the user wants them.
  532.     if {!$indentUsingSpacesOnly && [string length $sp]} {
  533.     while {[regsub -all "((^|\r|\n)\t*)$sp" $text "\\1\t" text]} {}
  534.     }
  535.     return $text
  536. }
  537.  
  538. proc text::halfTab {} {
  539.     global indent_amounts
  540.     return [string range "              " 1 $indent_amounts(1)]
  541. }
  542. proc text::Tab {} {
  543.     global indentationAmount
  544.     return [text::indentOf $indentationAmount]
  545. }
  546.  
  547. proc text::getTabSize {} {
  548.     getWinInfo a
  549.     return $a(tabsize)
  550. }
  551.  
  552. # ◊◊◊◊ General purpose indentation ◊◊◊◊ #
  553.  
  554. proc indentSelection {} {
  555.     mode::proc indentRegion
  556. }
  557.  
  558. ## 
  559.  # -------------------------------------------------------------------------
  560.  # 
  561.  # "text::inCommentBlock" --
  562.  # 
  563.  #  Returns 'startpos endpos' if true, else returns an error.  Not 
  564.  #  particularly robust, but not too bad either
  565.  # -------------------------------------------------------------------------
  566.  ##
  567. proc text::inCommentBlock {pos} {
  568.     set chars [comment::Characters Paragraph]
  569.     set start [string trim [lindex $chars 0]]
  570.     set end [string trim [lindex $chars 1]]
  571.     if {$start == $end} {
  572.     error "No"
  573.     }
  574.     set cS [search -s -f 0 -r 0 -l [pos::math $pos - 1000] $start $pos]
  575.     set cE [search -s -f 1 -r 0 -l [pos::math $pos + 1000] $end [lindex $cS 1]]
  576.     if {[pos::compare $pos >= [lindex $cE 1]]} {    
  577.     error "No"
  578.     } else {
  579.     return [list [lindex $cS 0] [lindex $cE 1]]
  580.     }
  581. }
  582.  
  583.  
  584. # Tom's new regexp which I don't use now.  Shame.
  585. #set commentRegexp       {/\*[^*]*\*+([^/*][^*]*\*+)*/}
  586.  
  587. #########################################################################
  588. # Generic C-style indentation (works for Tcl and Perl)
  589. # Significant changes by Vince.
  590. proc ::indentLine {} {
  591.     global commentsArentSpecialWhenIndenting
  592.     # get details of current line
  593.     set beg [lineStart [set p [getPos]]]
  594.     set text [getText $beg [nextLineStart $beg]]
  595.     regexp "^\[ \t\]*" $text white
  596.     set len [string length $white]
  597.     set epos [pos::math $beg + $len]
  598.  
  599.     if {[pos::compare $beg != [minPos]]} {
  600.     # Find last previous non-comment line and get its leading whitespace
  601.     set pos $beg
  602.     while 1 {
  603.         if {[pos::compare $pos == [minPos]] \
  604.           || [catch {search -s -f 0 -r 1 -i 0 -m 0 \
  605.           "^\[ \t\]*\[^ \t\r\n\]" [pos::math $pos - 1]} lst]} {
  606.         # search failed at top of file
  607.         set line "#"
  608.         set lwhite 0
  609.         break
  610.         }
  611.         if {!$commentsArentSpecialWhenIndenting && \
  612.           ![catch {text::inCommentBlock [lindex $lst 0]} res]} {
  613.         set pos [lindex $res 0]
  614.         } else {
  615.         set line [getText [lindex $lst 0] \
  616.           [pos::math [nextLineStart [lindex $lst 0]] - 1]]
  617.         set lwhite [posX [pos::math [lindex $lst 1] - 1]]    
  618.         break
  619.         }
  620.     }
  621.     
  622.     regexp "(\[^ \t\])\[ \t\]*\$" $line "" nextC
  623.     global indentationAmount electricColon
  624.     if {($nextC == "\{")} {
  625.         incr lwhite $indentationAmount
  626.     } elseif {$nextC == ":" && $electricColon} {
  627.         incr lwhite [expr {$indentationAmount /2}]
  628.     }
  629.     
  630.     if {[regexp ":\[ \t\r\n\]*\$" $text] && $electricColon} {
  631.         incr lwhite [expr {-$indentationAmount / 2}]
  632.     }
  633.     if {[lookAt $epos] == "\}"} {
  634.         incr lwhite [expr {-$indentationAmount}]
  635.     }
  636.     } else {
  637.     set lwhite 0
  638.     }
  639.     set lwhite [text::indentOf $lwhite]
  640.     if {$white != $lwhite} {
  641.     replaceText $beg $epos $lwhite
  642.     }
  643.     goto [pos::math $beg + [string length $lwhite]]
  644.     # To keep relative position.
  645.     #goto [pos::math $p + [string length $lwhite] - [pos::diff $beg $epos]]
  646. }
  647.  
  648.  
  649. proc ::indentRegion {} {
  650.     set from [lindex [posToRowCol [getPos]] 0]
  651.     set to [lindex [posToRowCol [selEnd]] 0]
  652.     select [getPos]
  653.     while {$from <= $to} {
  654.     goto [rowColToPos $from 0]
  655.     bind::IndentLine
  656.     incr from
  657.     }
  658. }
  659.